import 'dart:typed_data';
import 'package:flutter_blue_plus/flutter_blue_plus.dart';
import 'package:get/get.dart';
import 'package:synchronized/synchronized.dart';
import 'package:wk_robot2/app/const/AppConst.dart';
import 'package:wk_robot2/app/event/DataCallBack.dart';
import 'package:wk_robot2/app/storage/StorageManager.dart';
import '../logger/Logger.dart';
import '../modules/bindtip/views/bindtip_view.dart';
import '../routes/app_pages.dart';
import '../utils/CommonUtil.dart';
import '../widget/tips.dart';
import 'RobotCommands.dart';
import 'msgproto/BleMsgHandleEngine.dart';

class BltManager {
    static BltManager? _instance;

    static BltManager get instance => _instance ??= BltManager();


    Map<String, int> scanDevicesMap = {};
    Map<String, int> hittingDevicesMap = {};

    List<BluetoothService>? mBltservices;

    BluetoothDevice? mBluetoothDevice;
    var lock = new Lock();

    static const BLUE_TEETH_IDENTITIES = '07303e62-cb70-38d8-8f5c-40c062145442';
    static const UUID_SERVICE = "10057e66-28bd-4c3e-a030-08b4982739bc";
    static const UUID_WRITE_CHARACTER = "d2f9ff26-ad08-4bd3-8436-9b8f33bdea76";
    static const UUID_READ_CHARACTER = "7e0dffa2-c44f-48ac-a39e-3fce46d9aabb";


    static String mPendMsg = '';

    int tryScanTimes = 0;


    BltManager() {
      // 打开日志.
      FlutterBluePlus.setLogLevel(LogLevel.debug, color:true);
      init();
    }

    void init() async {
      if (await FlutterBluePlus.isSupported == false) {
        logger.info("Bluetooth not supported by this device");
        Tips.showToast('此设备不支持蓝牙');
        return;
      }

      FlutterBluePlus.adapterState.listen((BluetoothAdapterState state) {
        if (state == BluetoothAdapterState.on) {
          logger.info('当前蓝牙 打开了.');

          // usually start scanning, connecting, etc
          //toScan(dataCallBack: scanDeviceCallBack,timeout: timeout);
        } else {
          logger.info('当前蓝牙 关闭了.');
        }
      });
    }


    void toScan({int timeout =3, DataCallBack? dataCallBack, RxMap? deviceMap, bool justScan = false}) async {
      hittingDevicesMap.clear();

      var subscription = FlutterBluePlus.onScanResults.listen((results) {
        if (results.isNotEmpty) {
           results.forEach((r) {
                logger.info('attation::: ${r.device.remoteId}: ${r.advertisementData.advName}, ssi: ${r.rssi} found!');

                if (deviceMap != null) {
                  if (r.advertisementData.advName.trim() != '') {
                    deviceMap![r.advertisementData.advName] = r.device;
                  }
                }



                int cacheRssi = -10000;
                if(scanDevicesMap.containsKey(r.advertisementData.advName)) {
                  cacheRssi = scanDevicesMap[r.advertisementData.advName]!;
                }


                if (r.rssi > -53 && cacheRssi > -59 && !justScan) { // 最近的,信号最强.
                  logger.info('选中的设备:  current rssi: ${r.rssi}, cache rssi: ${cacheRssi}, scanDevicesMap: ${scanDevicesMap}');
                  hittingDevicesMap[r.advertisementData.advName] = r.rssi;
                  FlutterBluePlus.stopScan();
                  String robotUserId = 'unknow_identity';
                  List<String> advNames = r.advertisementData.advName.split('_');
                  if (advNames.length == 2) {
                    robotUserId = advNames[1];
                  } else {
                    robotUserId = r.advertisementData.advName;
                  }

                  connectDevice(r.device,robotUserId, dataCallBack: dataCallBack);
                }

                scanDevicesMap[r.advertisementData.advName] = r.rssi;



          });


        }
      },
        onDone: () {
          logger.info('onDone ----------->');
        },
        onError: (e) => print(e),
      );

      // cleanup: cancel subscription when scanning stops

      FlutterBluePlus.cancelWhenScanComplete(subscription);


      // Start scanning w/ timeout
      // Optional: use `stopScan()` as an alternative to timeout
      await FlutterBluePlus.startScan(
          withServices:[Guid(BLUE_TEETH_IDENTITIES)], // match any of the specified services
          withNames:["WK"], // *or* any of the specified names
          timeout: Duration(seconds:timeout)).catchError((e) {

            logger.info('搜索机器人超时了 ${e}');
      });

      // wait for scanning to stop
      await FlutterBluePlus.isScanning.where((val) => val == false).first;

      if (justScan) { //手动扫描的逻辑.
        if (deviceMap!.isEmpty) {
          dataCallBack!.errorCallBack!(HardwareCommands.SCAN_DEVICE_ERROR_NO_FOUND);
        }

        return;
      }


      logger.info('扫描到设备清单 --------------- scanDevicesMap.length: ${scanDevicesMap.length}');
      logger.info('击中的设备 --------------- hittingDevicesMap.length: ${hittingDevicesMap.length}, hittingDevicesMap:: ${hittingDevicesMap}');

      if (hittingDevicesMap.length == 0) { // 扫描结束未找到设备,重新搜索.
        dataCallBack!.errorCallBack!(HardwareCommands.SCAN_DEVICE_RECONNECTED);
      }

    }

    BluetoothDevice? getCurrentDevice() {
       return mBluetoothDevice;
    }


    void connectDevice(BluetoothDevice device,String robotUserId, {DataCallBack? dataCallBack, isNeedShowTips = false}) async {
      mBluetoothDevice = device;
      device.connect(timeout: Duration(seconds: 10)).then((v) async {
        BluetoothConnectionState state = await device.connectionState.first;
        logger.info('自动连接状态: ${state}');
        if (state == BluetoothConnectionState.connected) {
          StorageManager.getStorage().write(AppConst.BLT_DEVICE_SN_CURRENTLY_TMP, robotUserId);

          discoveryServices(device: device!);

          if (dataCallBack != null) {
            dataCallBack.deviceCallBack!({
              'device': device!
            });
          }



        } else if (state == BluetoothConnectionState.disconnected) {
          logger.info('机器人${robotUserId} 断开连接了,正在搜索下一个...');
          dataCallBack!.errorCallBack!(HardwareCommands.SCAN_DEVICE_RECONNECTED);

        }

      }).catchError((e) {
        logger.info('机器人${robotUserId} 连接异常了,正在搜索下一个... ${e}');
        dataCallBack!.errorCallBack!(HardwareCommands.SCAN_DEVICE_RECONNECTED);
      });

    }

    //专门为手工连接设备使用.
    void connectDeviceManual(BluetoothDevice device,String robotUserId, {DataCallBack? dataCallBack, isNeedShowTips = false}) async {
      mBluetoothDevice = device;
      device.connect().then((v) async {
        BluetoothConnectionState state = await device.connectionState.first;
        logger.info('手工连接状态: ${state}');

        if (state == BluetoothConnectionState.connected) {
          StorageManager.getStorage().write(AppConst.BLT_DEVICE_SN_CURRENTLY_TMP, robotUserId);

          discoveryServices(device: device);

          if (dataCallBack != null) {
            dataCallBack.deviceCallBack!({
              'device': device
            });
          }
        } else {
          if (dataCallBack != null) {
            dataCallBack.errorCallBack!('');
          }
        }
      }).catchError((e){
        logger.info('手工连接状态,连接异常. ${e}');
        if (dataCallBack != null) {
          dataCallBack.errorCallBack!('');
        }
      });


    }


    void discoveryServices({BluetoothDevice? device}) async {
      mBltservices = await device!.discoverServices();
      if (mBltservices == null) {
        discoveryServices(device: device);
      }

    }


    BluetoothCharacteristic? findCharacteristic(String serviceId,String uuid) {
       if(mBltservices == null) {
         logger.info('蓝牙发现服务失败,请重新尝试.');
         Get.offNamed(Routes.BINDTIP,arguments: {
           'type':'ERROR_NO_FOUND_SERVICES'
         });

         return null;
       }
       try {
         BluetoothCharacteristic? characteristic = mBltservices!
             .expand((service) => service.characteristics)
             .firstWhere((characteristic) =>
         characteristic.uuid.toString().toUpperCase() == uuid.toUpperCase() &&
             characteristic.serviceUuid.toString().toUpperCase() == serviceId.toUpperCase());

         return characteristic;
       } catch(e) {
         Get.offNamed(Routes.BINDTIP);
       }

    }




    Future<void> write(Uint8List commands,DataCallBack dataCallBack) async {
      var writeCharacter = BltManager.instance.findCharacteristic(UUID_SERVICE,UUID_WRITE_CHARACTER);
      var readCharacter = BltManager.instance.findCharacteristic(UUID_SERVICE, UUID_READ_CHARACTER);
      if (writeCharacter == null || readCharacter == null) {
        return null;
      }

      try {
        // if (!readCharacter.isNotifying) {
         bool readNotifyFlag =  await readCharacter.setNotifyValue(true,timeout: 30);
         bool writeNotifyFlag = await writeCharacter.setNotifyValue(true, timeout: 30);
         logger.info("=====> notifyFlag:::  ${readNotifyFlag}, writeNotifyFlag: ${writeNotifyFlag}");
        //}
      } catch(e) {
        e.printInfo();

        Get.toNamed(Routes.BINDTIP,arguments: {
          'type': ERROR_CONNECTION_INTERUPTED
        });
      }


      try {
        logger.info("=====> write data to robot");
        await writeCharacter.write(commands,allowLongWrite: true, timeout: 30);
      } catch(e) {
        logger.warning("蓝牙写数据超时: Write to devices timeout.");
        Get.toNamed(Routes.BINDTIP,arguments: {
          'type': ERROR_CONNECTION_INTERUPTED
        });
      }

      try {
        readCharacter.onValueReceived.listen((value) async {
          await lock.synchronized(() async {
            logger.info("<==== readRobot response: $value");
            Uint8List pendMsg = CommonUtil.listToInt8List(value);
            String hexMsg = CommonUtil.uint8ListToHex(pendMsg);

            //这个地方需要用lock锁住,否则可能会重复.
            if(mPendMsg != hexMsg) { // 去除重复过来的指令数据.
              handleProtoBuffMsg(pendMsg,"",dataCallBack);
              mPendMsg = hexMsg;
            }
          });
        });

      } catch (e) {
        logger.warning("蓝牙读数据超时: No response received from device.");
        return null;
      }
    }



    void disConnectDevice() {
      if (getCurrentDevice() != null) {
        getCurrentDevice()!.disconnect();
      }

    }


 }



